import { useState, useEffect, useCallback, DependencyList } from 'react';

interface useLoading<A extends any[]>{
  (...args: A): Promise<void>
  loading: boolean
  fail: undefined | string
  autoRun: (args: A, isRun?: (...args: A) => boolean) => useLoading<A>,
}

export default function useLoading<A extends any[]>(
  callback: (...args: A) => Promise<void>,
  deps: DependencyList,
): useLoading<A> {
  const [loading, setLoging] = useState(false)
  const [fail, setFail] = useState<undefined | string>()
  const fn = useCallback(async (...args: A) => {
    try{
      setLoging(true)
      setFail(undefined)
      return await callback(...args)
    }catch(e){
      setFail(e.message || "未知错误")
    }finally{
      setLoging(false)
    }
  }, deps) as useLoading<A>
  fn.loading = loading
  fn.fail = fail
  fn.autoRun = function (
    args: A,
    isRun?: (...args: A) => boolean
  ) {
    useEffect(() => {
      if(this.loading){
        return
      }
      this.loading = true
      if(!isRun || isRun(...args)){
        this(...args)
      }
      return () => {
        this.loading = false
      }
    }, [...args])
    return this
  }
  return fn
}